Add a function to dump CSS nodes and styles
authorMatthias Clasen <mclasen@redhat.com>
Mon, 28 Dec 2015 06:09:54 +0000 (01:09 -0500)
committerMatthias Clasen <mclasen@redhat.com>
Sun, 3 Jan 2016 14:19:30 +0000 (09:19 -0500)
Add a gtk_style_context_to_string function that can serialize
a CSS node or tree of nodes, optionally including CSS properties
as well.

This will be useful in writing tests.

docs/reference/gtk/gtk3-sections.txt
gtk/gtkcssnode.c
gtk/gtkcssnodeprivate.h
gtk/gtkstylecontext.c
gtk/gtkstylecontext.h

index e5cd1ef7e7b17ee16c323aeab958223a27fad4ca..6d5c590de576653b65efea3429213ae96dfadb95 100644 (file)
@@ -6244,6 +6244,8 @@ gtk_style_context_set_frame_clock
 gtk_style_context_set_state
 gtk_style_context_set_scale
 gtk_style_context_get_scale
+GtkStyleContextPrintFlags
+gtk_style_context_to_string
 
 <SUBSECTION>
 GtkBorder
index fca7de0cecb99cdf4830a5280f6b05a59735660b..4bae4e51ea856f3dee2d76f5414f0b43518e5f35 100644 (file)
@@ -25,6 +25,8 @@
 #include "gtkmarshalers.h"
 #include "gtksettingsprivate.h"
 #include "gtktypebuiltins.h"
+#include "gtkcssstylepropertyprivate.h"
+#include "gtkcsssectionprivate.h"
 
 /*
  * CSS nodes are the backbone of the GtkStyleContext implementation and
@@ -1510,7 +1512,7 @@ GtkStyleProviderPrivate *
 gtk_css_node_get_style_provider (GtkCssNode *cssnode)
 {
   GtkStyleProviderPrivate *result;
-  
+
   result = gtk_css_node_get_style_provider_or_null (cssnode);
   if (result)
     return result;
@@ -1520,3 +1522,189 @@ gtk_css_node_get_style_provider (GtkCssNode *cssnode)
 
   return GTK_STYLE_PROVIDER_PRIVATE (_gtk_settings_get_style_cascade (gtk_settings_get_default (), 1));
 }
+
+static void
+append_id (GtkCssNode *cssnode,
+           GString    *string)
+{
+  const char *id;
+
+  id = gtk_css_node_get_id (cssnode);
+  if (id)
+    {
+      g_string_append (string, " id=");
+      g_string_append (string, id);
+    }
+}
+
+static void
+append_visible (GtkCssNode *cssnode,
+                GString    *string)
+{
+  g_string_append_printf (string, " visible=%d", gtk_css_node_get_visible (cssnode));
+}
+
+static void
+append_state (GtkCssNode *cssnode,
+              GString    *string)
+
+{
+  GtkStateFlags state;
+
+  state = gtk_css_node_get_state (cssnode);
+  if (state)
+    {
+      GFlagsClass *fclass;
+      gint i;
+      gboolean first = TRUE;
+
+      g_string_append (string, " state=");
+      fclass = g_type_class_ref (GTK_TYPE_STATE_FLAGS);
+      for (i = 0; i < fclass->n_values; i++)
+        {
+          if (state & fclass->values[i].value)
+            {
+              if (first)
+                first = FALSE;
+              else
+                g_string_append_c (string, '|');
+              g_string_append (string, fclass->values[i].value_nick);
+            }
+        }
+      g_type_class_unref (fclass);
+    }
+}
+
+static void
+append_classes (GtkCssNode *cssnode,
+                GString    *string)
+{
+  const GQuark *classes;
+  guint n_classes;
+
+  classes = gtk_css_node_list_classes (cssnode, &n_classes);
+  if (n_classes > 0)
+    {
+      int i;
+
+      g_string_append (string, " classes=");
+      for (i = 0; i < n_classes; i++)
+        {
+          if (i > 0)
+            g_string_append_c (string, ',');
+          g_string_append (string, g_quark_to_string (classes[i]));
+        }
+    }
+}
+
+static gboolean
+gtk_css_node_has_initial_value (GtkCssNode          *cssnode,
+                                GtkCssStyleProperty *prop)
+{
+  GtkCssNode *parent_node;
+  GtkCssStyle *style, *parent_style;
+  GtkCssValue *value, *initial, *computed;
+  GtkCssProvider *provider;
+  gboolean is_initial;
+  guint id;
+
+  id = _gtk_css_style_property_get_id (prop);
+  style = gtk_css_node_get_style (cssnode);
+  value = gtk_css_style_get_value (style, id);
+
+  parent_node = gtk_css_node_get_parent (cssnode);
+  parent_style = parent_node ? gtk_css_node_get_style (parent_node) : NULL;
+  provider = gtk_css_node_get_style_provider (cssnode);
+
+  initial = _gtk_css_style_property_get_initial_value (prop);
+  computed = _gtk_css_value_compute (initial, id, provider, style, parent_style);
+
+  is_initial = _gtk_css_value_equal (value, computed);
+
+  _gtk_css_value_unref (computed);
+
+  return is_initial;
+}
+
+static void
+append_value (GtkCssNode          *cssnode,
+              GtkCssStyleProperty *prop,
+              GString             *string,
+              guint                indent)
+{
+  GtkCssValue *value;
+  GtkCssStyle *style;
+  GtkCssSection *section;
+  const char *name;
+  guint id;
+
+  id = _gtk_css_style_property_get_id (prop);
+  name = _gtk_style_property_get_name (GTK_STYLE_PROPERTY (prop));
+  style = gtk_css_node_get_style (cssnode);
+  value = gtk_css_style_get_value (style, id);
+
+  g_string_append_printf (string, "%*s%s: ", indent, "", name);
+
+  _gtk_css_value_print (value, string);
+
+  section = gtk_css_style_get_section (style, id);
+  if (section)
+    {
+      g_string_append (string, " (");
+      _gtk_css_section_print (section, string);
+      g_string_append (string, ")");
+    }
+
+  g_string_append_c (string, '\n');
+}
+
+static void
+append_style (GtkCssNode                *cssnode,
+              GtkStyleContextPrintFlags  flags,
+              GString                   *string,
+              guint                      indent)
+{
+  int i;
+
+  if (!(flags & GTK_STYLE_CONTEXT_PRINT_SHOW_STYLE))
+    return;
+
+  for (i = 0; i < _gtk_css_style_property_get_n_properties (); i++)
+    {
+      GtkCssStyleProperty *prop;
+
+      prop = _gtk_css_style_property_lookup_by_id (i);
+
+      if ((flags & GTK_STYLE_CONTEXT_PRINT_SHOW_INITIAL) ||
+          !gtk_css_node_has_initial_value (cssnode, prop))
+        append_value (cssnode, prop, string, indent);
+    }
+}
+
+void
+gtk_css_node_print (GtkCssNode                *cssnode,
+                    GtkStyleContextPrintFlags  flags,
+                    GString                   *string,
+                    guint                      indent)
+{
+  GtkCssNode *node;
+
+  g_string_append_printf (string, "%*s", indent, "");
+  if (gtk_css_node_get_name (cssnode))
+    g_string_append (string, gtk_css_node_get_name (cssnode));
+  else
+    g_string_append (string, g_type_name (gtk_css_node_get_widget_type (cssnode)));
+  append_id (cssnode, string);
+  append_visible (cssnode, string);
+  append_state (cssnode, string);
+  append_classes (cssnode, string);
+  g_string_append_c (string, '\n');
+
+  append_style (cssnode, flags, string, indent + 2);
+
+  if (flags & GTK_STYLE_CONTEXT_PRINT_RECURSE)
+    {
+      for (node = gtk_css_node_get_first_child (cssnode); node; node = gtk_css_node_get_next_sibling (node))
+        gtk_css_node_print (node, flags, string, indent + 2);
+    }
+}
index 8624a51678410bf7aa42b96e754a2724c7d0d6c7..065b8e72a0ba6a706b7916514c4ff5bfca49908a 100644 (file)
@@ -171,6 +171,11 @@ GtkWidgetPath *         gtk_css_node_create_widget_path (GtkCssNode            *
 const GtkWidgetPath *   gtk_css_node_get_widget_path    (GtkCssNode            *cssnode);
 GtkStyleProviderPrivate *gtk_css_node_get_style_provider(GtkCssNode            *cssnode);
 
+void                    gtk_css_node_print              (GtkCssNode                *cssnode,
+                                                         GtkStyleContextPrintFlags  flags,
+                                                         GString                   *string,
+                                                         guint                      indent);
+
 G_END_DECLS
 
 #endif /* __GTK_CSS_NODE_PRIVATE_H__ */
index 7fe5f3cf8a6b7f5b08808dc5fd64f71e36734bea..30173c7c158f26f71ba2e13dfb9aa76a01a6f40e 100644 (file)
@@ -3219,3 +3219,53 @@ _gtk_style_context_is_background_opaque (GtkStyleContext *context)
           corner_value_is_right_angle (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_BOTTOM_RIGHT_RADIUS)) &&
           corner_value_is_right_angle (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_BOTTOM_LEFT_RADIUS)));
 }
+
+/**
+ * GtkStyleContextPrintFlags:
+ * @GTK_STYLE_CONTEXT_PRINT_RECURSE: Print the entire tree of
+ *     CSS nodes starting at the style context's node
+ * @GTK_STYLE_CONTEXT_PRINT_SHOW_STYLE: Show the values of the
+ *     CSS properties for each node
+ * @GTK_STYLE_CONTEXT_PRINT_SHOW_INITIAL: Show the values of the
+ *     CSS properties even if they match the initial value. By default,
+ *     values are only shown if they are different from the initial
+ *     value.
+ *
+ * Flags that modify the behavior of gtk_style_context_to_string().
+ * New values may be added to this enumeration.
+ */
+
+/**
+ * gtk_style_context_to_string:
+ * @context: a #GtkStyleContext
+ * @flags: Flags that determine what to print
+ *
+ * Converts the style context into a string representation.
+ *
+ * The string representation always includes information about
+ * the name, state, id, visibility and style classes of the CSS
+ * node that is backing @context. Depending on the flags, more
+ * information may be included.
+ *
+ * This function is intended for testing and debugging of the
+ * CSS implementation in GTK+. There are no guarantees about
+ * the format of the returned string, it may change.
+ *
+ * Returns: a newly allocated string representing @context
+ *
+ * Since: 3.20
+ */
+char *
+gtk_style_context_to_string (GtkStyleContext           *context,
+                             GtkStyleContextPrintFlags  flags)
+{
+  GString *string;
+
+  g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
+
+  string = g_string_new ("");
+
+  gtk_css_node_print (context->priv->cssnode, flags, string, 0);
+
+  return g_string_free (string, FALSE);
+}
index 8428213b2691b69b455ae1621b083e6a9dc45243..d6fe5754f7eb0ad68b312a79fe0e79b224ca9961 100644 (file)
@@ -1208,6 +1208,17 @@ void   gtk_draw_insertion_cursor    (GtkWidget          *widget,
                                      GtkTextDirection    direction,
                                      gboolean            draw_arrow);
 
+typedef enum {
+  GTK_STYLE_CONTEXT_PRINT_NONE         = 0,
+  GTK_STYLE_CONTEXT_PRINT_RECURSE      = 1 << 0,
+  GTK_STYLE_CONTEXT_PRINT_SHOW_STYLE   = 1 << 1,
+  GTK_STYLE_CONTEXT_PRINT_SHOW_INITIAL = 1 << 2
+} GtkStyleContextPrintFlags;
+
+GDK_AVAILABLE_IN_3_20
+char * gtk_style_context_to_string (GtkStyleContext           *context,
+                                    GtkStyleContextPrintFlags  flags);
+
 G_END_DECLS
 
 #endif /* __GTK_STYLE_CONTEXT_H__ */